
/*@internal*/
名域 ts {
    /**
     * State to store the changed files, affected files and cache semantic diagnostics
     */
    导出 接口 构建程序状态_ 扩展 构建状态_ {
        /**
         * Cache of semantic diagnostics for files with their 路径_ being the key
         */
        之前文件的语义诊断: 词典_<只读数组_<诊断_>> | 未定;
        /**
         * The map has key by source 文件's 路径 that has been changed
         */
        检查文件集合: 词典_<为真>;
        /**
         * Set of affected files being iterated
         */
        受影响文件组: 只读数组_<源文件_> | 未定;
        /**
         * Current index to retrieve affected 文件 from
         */
        受影响的文件索引: 数字 | 未定;
        /**
         * Current changed 文件 for iterating over affected files
         */
        当前改变文件路径: 路径_ | 未定;
        /**
         * 词典_ of 文件 signatures, with key being 文件 路径, calculated while getting 当前 changed 文件's affected files
         * These will be commited whenever the iteration through affected files of 当前 changed 文件 is complete
         */
        当前受影响文件签名: 词典_<文字> | 未定;
        /**
         * Already seen affected files
         */
        看受影响的文件: 词典_<为真> | 未定;
        /**
         * program corresponding to this 状态
         */
        程序: 程序_;
    }

    函数 具有相同键<T, U>(词典1: 词典_<T> | 未定, 词典2: 词典_<U> | 未定): 真假 {
        // Has same size and every key is present in both maps
        返回 !!(词典1 转为 词典_<T | U> === 词典2 || 词典1 && 词典2 && 词典1.大小 === 词典2.大小 && !循环每个键(词典1, 键 => !词典2.具有(键)));
    }

    /**
     * Create the 状态 so that we can iterate on changedFiles/affected files
     */
    函数 创建构建者程序状态(新程序: 程序_, 旧状态?: 只读_<构建程序状态_>): 构建程序状态_ {
        常量 状态 = 构建状态_.创建(新程序, 旧状态) 转为 构建程序状态_;
        状态.程序 = 新程序;
        常量 编译选项 = 新程序.获取编译选项();
        如果 (!编译选项.outFile && !编译选项.out) {
            状态.之前文件的语义诊断 = 创建词典<只读数组_<诊断_>>();
        }
        状态.检查文件集合 = 创建词典<为真>();
        常量 使用就状态 = !!构建状态_.可以重用旧状态(状态.引用词典!, 旧状态);
        常量 可以复制语言诊断 = 使用就状态 && 旧状态!.之前文件的语义诊断 && !!状态.之前文件的语义诊断;
        如果 (使用就状态) {
            // Verify the sanity of old 状态
            如果 (!旧状态!.当前改变文件路径) {
                调试_.断言(!旧状态!.受影响文件组 && (!旧状态!.当前受影响文件签名 || !旧状态!.当前受影响文件签名.大小), '如果仅迭代了当前更改文件的少数受影响文件，则无法重复使用.');
            }
            如果 (可以复制语言诊断) {
                调试_.断言(!循环每个键(旧状态!.检查文件集合, 路径 => 旧状态!.之前文件的语义诊断!.具有(路径)), '语义诊断不应可用于更改的文件.');
            }

            // Copy old 状态's changed files set
            复制条目(旧状态!.检查文件集合, 状态.检查文件集合);
        }

        // Update changed files and copy semantic diagnostics if we can
        常量 引用词典 = 状态.引用词典;
        常量 旧的引用词典 = 使用就状态 && 旧状态!.引用词典;
        状态.文件信息组.循环执行((信息, 源文件路径) => {
            变量 旧信息: 只读_<构建状态_.文件信息_>;
            变量 新引用组: 构建状态_.引用集合_ | 未定;

            // if not using old 状态, every 文件 is changed
            如果 (!使用就状态 ||
                // File wasnt present in old 状态
                !(旧信息 = 旧状态!.文件信息组.获取(源文件路径)!) ||
                // versions dont match
                旧信息.版本 !== 信息.版本 ||
                // Referenced files changed
                !具有相同键(新引用组 = 引用词典 && 引用词典.获取(源文件路径)!, 旧的引用词典 ? 旧的引用词典.获取(源文件路径) : 未定) ||
                // Referenced 文件 was deleted in the new program
                新引用组 && 循环每个键(新引用组, 路径 => !状态.文件信息组.具有(路径) && 旧状态!.文件信息组.具有(路径))) {
                // Register 文件 as changed 文件 and do not copy semantic diagnostics, since all changed files need to be re-evaluated
                状态.检查文件集合.设置(源文件路径, 为真);
            }
            否则 如果 (可以复制语言诊断) {
                // Unchanged 文件 copy diagnostics
                常量 诊断组 = 旧状态!.之前文件的语义诊断!.获取(源文件路径);
                如果 (诊断组) {
                    状态!.之前文件的语义诊断!.设置(源文件路径, 诊断组);
                }
            }
        });

        返回 状态;
    }

    /**
     * Verifies that source 文件 is ok to be used in calls that arent handled by next
     */
    函数 断言源文件确定没有下一个受影响的调用(状态: 构建程序状态_, 源文件: 源文件_ | 未定) {
        调试_.断言(!源文件 || !状态.受影响文件组 || 状态.受影响文件组[状态.受影响的文件索引! - 1] !== 源文件 || !状态.之前文件的语义诊断!.具有(源文件.路径));
    }

    /**
     * This function returns the next affected 文件 to be processed.
     * Note that until doneAffected is called it would keep reporting same 结果
     * This is to allow the callers to be able to actually remove affected 文件 only when the operation is complete
     * eg. if during diagnostics check cancellation 令牌 ends up cancelling the request, the affected 文件 should be retained
     */
    函数 获取下个受影响的文件(状态: 构建程序状态_, 取消令牌: 取消令牌_ | 未定, 计算哈希: 构建状态_.计算哈希_): 源文件_ | 程序_ | 未定 {
        判断 (为真) {
            常量 { 受影响文件组 } = 状态;
            如果 (受影响文件组) {
                常量 { 看受影响的文件, 之前文件的语义诊断 } = 状态;
                变量 { 受影响的文件索引 } = 状态;
                判断 (受影响的文件索引! < 受影响文件组.长度) {
                    常量 受影响文件 = 受影响文件组[受影响的文件索引!];
                    如果 (!看受影响的文件!.具有(受影响文件.路径)) {
                        // Set the next affected 文件 as seen and remove the cached semantic diagnostics
                        状态.受影响的文件索引 = 受影响的文件索引;
                        之前文件的语义诊断!.删除(受影响文件.路径);
                        返回 受影响文件;
                    }
                    看受影响的文件!.设置(受影响文件.路径, 为真);
                    受影响的文件索引!++;
                }

                // Remove the changed 文件 from the change set
                状态.检查文件集合.删除(状态.当前改变文件路径!);
                状态.当前改变文件路径 = 未定;
                // Commit the changes in 文件 签名
                构建状态_.更新签名从缓存(状态, 状态.当前受影响文件签名!);
                状态.当前受影响文件签名!.清除();
                状态.受影响文件组 = 未定;
            }

            // Get next changed 文件
            常量 下个键 = 状态.检查文件集合.键组().next();
            如果 (下个键.done) {
                // Done
                返回 未定;
            }

            // With --out or --outFile all outputs go into single 文件
            // so operations are performed directly on program, return program
            常量 编译选项 = 状态.程序.获取编译选项();
            如果 (编译选项.outFile || 编译选项.out) {
                调试_.断言(!状态.之前文件的语义诊断);
                返回 状态.程序;
            }

            // Get next batch of affected files
            状态.当前受影响文件签名 = 状态.当前受影响文件签名 || 创建词典();
            状态.受影响文件组 = 构建状态_.获取受影响文件从(状态, 状态.程序, 下个键.值 转为 路径_, 取消令牌, 计算哈希, 状态.当前受影响文件签名);
            状态.当前改变文件路径 = 下个键.值 转为 路径_;
            状态.之前文件的语义诊断!.删除(下个键.值 转为 路径_);
            状态.受影响的文件索引 = 0;
            状态.看受影响的文件 = 状态.看受影响的文件 || 创建词典<为真>();
        }
    }

    /**
     * This is called after completing operation on the next affected 文件.
     * The operations here are postponed to ensure that cancellation during the iteration is handled correctly
     */
    函数 完成包含受影响的文件(状态: 构建程序状态_, 受影响的: 源文件_ | 程序_) {
        如果 (受影响的 === 状态.程序) {
            状态.检查文件集合.清除();
        }
        否则 {
            状态.看受影响的文件!.设置((受影响的 转为 源文件_).路径, 为真);
            状态.受影响的文件索引!++;
        }
    }

    /**
     * Returns the 结果 with affected 文件
     */
    函数 转成受影响文件结果<T>(状态: 构建程序状态_, 结果: T, 受影响的: 源文件_ | 程序_): 受影响的文件结果<T> {
        完成包含受影响的文件(状态, 受影响的);
        返回 { 结果, 受影响的 };
    }

    /**
     * Gets the semantic diagnostics either from cache if present, or otherwise from program and caches it
     * Note that it is assumed that the when asked about semantic diagnostics, the 文件 has been taken out of affected files/changed 文件 set
     */
    函数 获取文件的语义诊断(状态: 构建程序状态_, 源文件: 源文件_, 取消令牌?: 取消令牌_): 只读数组_<诊断_> {
        常量 路径 = 源文件.路径;
        常量 缓存诊断 = 状态.之前文件的语义诊断!.获取(路径);
        // Report the semantic diagnostics from the cache if we already have those diagnostics present
        如果 (缓存诊断) {
            返回 缓存诊断;
        }

        // 诊断信息_ werent cached, get them from program, and cache the 结果
        常量 诊断组 = 状态.程序.获取语义诊断信息(源文件, 取消令牌);
        状态.之前文件的语义诊断!.设置(路径, 诊断组);
        返回 诊断组;
    }

    导出 枚举 构建程序种类_ {
        语义诊断生成器_,
        输出和语义诊断生成器_
    }

    导出 接口 构建创建参数_ {
        新程序: 程序_;
        主机: 构建程序主机_;
        旧程序: 构建程序_ | 未定;
    }

    导出 函数 获取构建创建参数(新程序或根名称组: 程序_ | 只读数组_<文字>, 主机或选项: 构建程序主机_ | 编译选项_, 旧程序或主机?: 编译主机_ | 构建程序_, 旧程序?: 构建程序_): 构建创建参数_ {
        变量 主机: 构建程序主机_;
        变量 新程序: 程序_;
        如果 (是数组(新程序或根名称组) || !新程序或根名称组) {
            新程序 = 创建程序(新程序或根名称组, 主机或选项 转为 编译选项_, 旧程序或主机 转为 编译主机_, 旧程序 && 旧程序.获取程序());
            主机 = 旧程序或主机 转为 编译主机_;
        }
        否则 {
            新程序 = 新程序或根名称组;
            主机 = 主机或选项 转为 构建程序主机_;
            旧程序 = 旧程序或主机 转为 构建程序_;
        }
        返回 { 主机, 新程序, 旧程序 };
    }

    导出 函数 创建构建程序(种类: 构建程序种类_.语义诊断生成器_, 构建创建参数: 构建创建参数_): 语义诊断构建器程序_;
    导出 函数 创建构建程序(种类: 构建程序种类_.输出和语义诊断生成器_, 构建创建参数: 构建创建参数_): 输出和可视化语义诊断构建程序_;
    导出 函数 创建构建程序(种类: 构建程序种类_, { 新程序, 主机, 旧程序 }: 构建创建参数_) {
        // Return same program if underlying program doesnt change
        变量 旧状态 = 旧程序 && 旧程序.获取状态();
        如果 (旧状态 && 新程序 === 旧状态.程序) {
            新程序 = 未定!;
            旧状态 = 未定;
            返回 旧程序;
        }

        /**
         * Computing 井号_ to for 签名 verification
         */
        常量 计算哈希 = 主机.创建哈希 || 身份;
        常量 状态 = 创建构建者程序状态(新程序, 旧状态);

        // To ensure that we arent storing any references to old program or new program without 状态
        新程序 = 未定!;
        旧程序 = 未定;
        旧状态 = 未定;

        常量 结果: 构建程序_ = {
            获取状态: () => 状态,
            获取程序: () => 状态.程序,
            获取编译选项: () => 状态.程序.获取编译选项(),
            获取源文件: 文件名 => 状态.程序.获取源文件(文件名),
            获取源文件组: () => 状态.程序.获取源文件组(),
            获取选项诊断信息: 取消令牌 => 状态.程序.获取选项诊断信息(取消令牌),
            获取全局诊断信息: 取消令牌 => 状态.程序.获取全局诊断信息(取消令牌),
            获取语法诊断信息: (源文件, 取消令牌) => 状态.程序.获取语法诊断信息(源文件, 取消令牌),
            获取语义诊断信息: 获取语义诊断信息,
            输出: 输出,
            获取全部诊断信息: 源文件 => 构建状态_.获取全部诊断信息(状态, 状态.程序, 源文件),
            获取当前目录: () => 状态.程序.获取当前目录()
        };

        如果 (种类 === 构建程序种类_.语义诊断生成器_) {
            (结果 转为 语义诊断构建器程序_).获取下个受影响的语义诊断 = 获取下个受影响文件的语义诊断;
        }
        否则 如果 (种类 === 构建程序种类_.输出和语义诊断生成器_) {
            (结果 转为 输出和可视化语义诊断构建程序_).输出下个受影响的文件 = 输出下个受影响文件;
        }
        否则 {
            未实现();
        }

        返回 结果;

        /**
         * Emits the next affected 文件's emit 结果 (EmitResult and sourceFiles emitted) or returns 未定 if iteration is complete
         * The 首个 of 写文件 if provided, 写文件 of BuilderProgramHost if provided, 写文件 of compiler 主机
         * in that order would be used to write the files
         */
        函数 输出下个受影响文件(写文件?: 写文件回调_, 取消令牌?: 取消令牌_, 输出仅Dk文件?: 真假, 自定义转换组?: 自定义转换器_): 受影响的文件结果<输出结果_> {
            常量 受影响的 = 获取下个受影响的文件(状态, 取消令牌, 计算哈希);
            如果 (!受影响的) {
                // Done
                返回 未定;
            }

            返回 转成受影响文件结果(
                状态,
                // When whole program is affected, do emit only once (eg when --out or --outFile is specified)
                // Otherwise just affected 文件
                状态.程序.输出(受影响的 === 状态.程序 ? 未定 : 受影响的 转为 源文件_, 写文件 || 主机.写文件, 取消令牌, 输出仅Dk文件, 自定义转换组),
                受影响的
            );
        }

        /**
         * Emits the JavaScript and declaration files.
         * When targetSource 文件 is specified, emits the files corresponding to that source 文件,
         * otherwise for the whole program.
         * In case of EmitAndSemanticDiagnosticsBuilderProgram, when targetSourceFile is specified,
         * it is assumed that that 文件 is handled from affected 文件 列表. If targetSourceFile is not specified,
         * it will only emit all the affected files instead of whole program
         *
         * The 首个 of 写文件 if provided, 写文件 of BuilderProgramHost if provided, 写文件 of compiler 主机
         * in that order would be used to write the files
         */
        函数 输出(目标源文件?: 源文件_, 写文件?: 写文件回调_, 取消令牌?: 取消令牌_, 输出仅Dk文件?: 真假, 自定义转换组?: 自定义转换器_): 输出结果_ {
            如果 (种类 === 构建程序种类_.输出和语义诊断生成器_) {
                断言源文件确定没有下一个受影响的调用(状态, 目标源文件);
                如果 (!目标源文件) {
                    // Emit and report any errors we ran into.
                    变量 源映射组: 源映射数据_[] = [];
                    变量 跳过输出!: 真假;
                    变量 诊断组!: 诊断_[];
                    变量 输出的文件: 文字[] = [];

                    变量 是影响的输出结果: 受影响的文件结果<输出结果_>;
                    判断 (是影响的输出结果 = 输出下个受影响文件(写文件, 取消令牌, 输出仅Dk文件, 自定义转换组)) {
                        跳过输出 = 跳过输出 || 是影响的输出结果.结果.输出跳过;
                        诊断组 = 添加范围(诊断组, 是影响的输出结果.结果.诊断组)!;
                        输出的文件 = 添加范围(输出的文件, 是影响的输出结果.结果.输出文件)!;
                        源映射组 = 添加范围(源映射组, 是影响的输出结果.结果.源映射)!;
                    }
                    返回 {
                        输出跳过: 跳过输出,
                        诊断组: 诊断组 || 空数组,
                        输出文件: 输出的文件,
                        源映射: 源映射组
                    };
                }
            }
            返回 状态.程序.输出(目标源文件, 写文件 || 主机.写文件, 取消令牌, 输出仅Dk文件, 自定义转换组);
        }

        /**
         * Return the semantic diagnostics for the next affected 文件 or 未定 if iteration is complete
         * If provided ignoreSourceFile would be called before getting the diagnostics and would ignore the 源文件 if the returned value was true
         */
        函数 获取下个受影响文件的语义诊断(取消令牌?: 取消令牌_, 忽略源文件?: (源文件: 源文件_) => 真假): 受影响的文件结果<只读数组_<诊断_>> {
            判断 (为真) {
                常量 受影响的 = 获取下个受影响的文件(状态, 取消令牌, 计算哈希);
                如果 (!受影响的) {
                    // Done
                    返回 未定;
                }
                否则 如果 (受影响的 === 状态.程序) {
                    // When whole program is affected, get all semantic diagnostics (eg when --out or --outFile is specified)
                    返回 转成受影响文件结果(
                        状态,
                        状态.程序.获取语义诊断信息(/*targetSourceFile*/ 未定, 取消令牌),
                        受影响的
                    );
                }

                // Get diagnostics for the affected 文件 if its not ignored
                如果 (忽略源文件 && 忽略源文件(受影响的 转为 源文件_)) {
                    // Get next affected 文件
                    完成包含受影响的文件(状态, 受影响的);
                    继续;
                }

                返回 转成受影响文件结果(
                    状态,
                    获取文件的语义诊断(状态, 受影响的 转为 源文件_, 取消令牌),
                    受影响的
                );
            }
        }

        /**
         * Gets the semantic diagnostics from the program corresponding to this 状态 of 文件 (if provided) or whole program
         * The semantic diagnostics are cached and managed here
         * Note that it is assumed that when asked about semantic diagnostics through this API,
         * the 文件 has been taken out of affected files so it is safe to use cache or get from program and cache the diagnostics
         * In case of SemanticDiagnosticsBuilderProgram if the source 文件 is not provided,
         * it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics
         */
        函数 获取语义诊断信息(源文件?: 源文件_, 取消令牌?: 取消令牌_): 只读数组_<诊断_> {
            断言源文件确定没有下一个受影响的调用(状态, 源文件);
            常量 编译选项组 = 状态.程序.获取编译选项();
            如果 (编译选项组.outFile || 编译选项组.out) {
                调试_.断言(!状态.之前文件的语义诊断);
                // We dont need to cache the diagnostics just return them from program
                返回 状态.程序.获取语义诊断信息(源文件, 取消令牌);
            }

            如果 (源文件) {
                返回 获取文件的语义诊断(状态, 源文件, 取消令牌);
            }

            如果 (种类 === 构建程序种类_.语义诊断生成器_) {
                // When semantic builder asks for diagnostics of the whole program,
                // ensure that all the affected files are handled
                变量 受影响的: 源文件_ | 程序_ | 未定;
                判断 (受影响的 = 获取下个受影响的文件(状态, 取消令牌, 计算哈希)) {
                    完成包含受影响的文件(状态, 受影响的);
                }
            }

            变量 诊断组!: 诊断_[];
            循环 (常量 源文件 属于 状态.程序.获取源文件组()) {
                诊断组 = 添加范围(诊断组, 获取文件的语义诊断(状态, 源文件, 取消令牌))!;
            }
            返回 诊断组 || 空数组;
        }
    }
}

名域 ts {
    导出 类型 受影响的文件结果<T> = { 结果: T; 受影响的: 源文件_ | 程序_; } | 未定;

    导出 接口 构建程序主机_ {
        /**
         * return true if 文件 names are treated with case sensitivity
         */
        使用区分大小写文件名(): 真假;
        /**
         * If provided this would be used this 井号_ instead of actual 文件 shape 文本 for detecting changes
         */
        创建哈希?: (数据: 文字) => 文字;
        /**
         * When emit or emitNextAffectedFile are called without 写文件,
         * this callback if present would be used to write files
         */
        写文件?: 写文件回调_;
    }

    /**
     * Builder to manage the program 状态 changes
     */
    导出 接口 构建程序_ {
        /*@internal*/
        获取状态(): 构建程序状态_;
        /**
         * Returns 当前 program
         */
        获取程序(): 程序_;
        /**
         * Get compiler 选项组 of the program
         */
        获取编译选项(): 编译选项_;
        /**
         * Get the source 文件 in the program with 文件 名称
         */
        获取源文件(文件名: 文字): 源文件_ | 未定;
        /**
         * Get a 列表 of files in the program
         */
        获取源文件组(): 只读数组_<源文件_>;
        /**
         * Get the diagnostics for compiler 选项组
         */
        获取选项诊断信息(取消令牌?: 取消令牌_): 只读数组_<诊断_>;
        /**
         * Get the diagnostics that dont belong to any 文件
         */
        获取全局诊断信息(取消令牌?: 取消令牌_): 只读数组_<诊断_>;
        /**
         * Get the syntax diagnostics, for all source files if source 文件 is not supplied
         */
        获取语法诊断信息(源文件?: 源文件_, 取消令牌?: 取消令牌_): 只读数组_<诊断_>;
        /**
         * Get all the dependencies of the 文件
         */
        获取全部诊断信息(源文件: 源文件_): 只读数组_<文字>;
        /**
         * Gets the semantic diagnostics from the program corresponding to this 状态 of 文件 (if provided) or whole program
         * The semantic diagnostics are cached and managed here
         * Note that it is assumed that when asked about semantic diagnostics through this API,
         * the 文件 has been taken out of affected files so it is safe to use cache or get from program and cache the diagnostics
         * In case of SemanticDiagnosticsBuilderProgram if the source 文件 is not provided,
         * it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics
         */
        获取语义诊断信息(源文件?: 源文件_, 取消令牌?: 取消令牌_): 只读数组_<诊断_>;
        /**
         * Emits the JavaScript and declaration files.
         * When targetSource 文件 is specified, emits the files corresponding to that source 文件,
         * otherwise for the whole program.
         * In case of EmitAndSemanticDiagnosticsBuilderProgram, when targetSourceFile is specified,
         * it is assumed that that 文件 is handled from affected 文件 列表. If targetSourceFile is not specified,
         * it will only emit all the affected files instead of whole program
         *
         * The 首个 of 写文件 if provided, 写文件 of BuilderProgramHost if provided, 写文件 of compiler 主机
         * in that order would be used to write the files
         */
        输出(目标源文件?: 源文件_, 写文件?: 写文件回调_, 取消令牌?: 取消令牌_, 输出仅Dk文件?: 真假, 自定义转换组?: 自定义转换器_): 输出结果_;
        /**
         * Get the 当前 directory of the program
         */
        获取当前目录(): 文字;
    }

    /**
     * The builder that caches the semantic diagnostics for the program and handles the changed files and affected files
     */
    导出 接口 语义诊断构建器程序_ 扩展 构建程序_ {
        /**
         * Gets the semantic diagnostics from the program for the next affected 文件 and caches it
         * Returns 未定 if the iteration is complete
         */
        获取下个受影响的语义诊断(取消令牌?: 取消令牌_, 忽略源文件?: (源文件: 源文件_) => 真假): 受影响的文件结果<只读数组_<诊断_>>;
    }

    /**
     * The builder that can handle the changes in program and iterate through changed 文件 to emit the files
     * The semantic diagnostics are cached per 文件 and managed by clearing for the changed/affected files
     */
    导出 接口 输出和可视化语义诊断构建程序_ 扩展 构建程序_ {
        /**
         * Emits the next affected 文件's emit 结果 (EmitResult and sourceFiles emitted) or returns 未定 if iteration is complete
         * The 首个 of 写文件 if provided, 写文件 of BuilderProgramHost if provided, 写文件 of compiler 主机
         * in that order would be used to write the files
         */
        输出下个受影响的文件(写文件?: 写文件回调_, 取消令牌?: 取消令牌_, 输出仅Dk文件?: 真假, 自定义转换组?: 自定义转换器_): 受影响的文件结果<输出结果_>;
    }

    /**
     * Create the builder to manage semantic diagnostics and cache them
     */
    导出 函数 创建语义诊断生成器程序(新程序: 程序_, 主机: 构建程序主机_, 旧程序?: 语义诊断构建器程序_): 语义诊断构建器程序_;
    导出 函数 创建语义诊断生成器程序(根名称组: 只读数组_<文字>, 选项组: 编译选项_, 主机?: 编译主机_, 旧程序?: 语义诊断构建器程序_): 语义诊断构建器程序_;
    导出 函数 创建语义诊断生成器程序(新程序或根文件名组: 程序_ | 只读数组_<文字>, 主机或选项: 构建程序主机_ | 编译选项_, 旧程序或主机?: 编译主机_ | 语义诊断构建器程序_, 旧程序?: 语义诊断构建器程序_) {
        返回 创建构建程序(构建程序种类_.语义诊断生成器_, 获取构建创建参数(新程序或根文件名组, 主机或选项, 旧程序或主机, 旧程序));
    }

    /**
     * Create the builder that can handle the changes in program and iterate through changed files
     * to emit the those files and manage semantic diagnostics cache as well
     */
    导出 函数 创建输出和语义诊断生成器程序(新程序: 程序_, 主机: 构建程序主机_, 旧程序?: 输出和可视化语义诊断构建程序_): 输出和可视化语义诊断构建程序_;
    导出 函数 创建输出和语义诊断生成器程序(根名称组: 只读数组_<文字>, 选项组: 编译选项_, 主机?: 编译主机_, 旧程序?: 输出和可视化语义诊断构建程序_): 输出和可视化语义诊断构建程序_;
    导出 函数 创建输出和语义诊断生成器程序(新程序或根文件名组: 程序_ | 只读数组_<文字>, 主机或选项: 构建程序主机_ | 编译选项_, 旧程序或主机?: 编译主机_ | 输出和可视化语义诊断构建程序_, 旧程序?: 输出和可视化语义诊断构建程序_) {
        返回 创建构建程序(构建程序种类_.输出和语义诊断生成器_, 获取构建创建参数(新程序或根文件名组, 主机或选项, 旧程序或主机, 旧程序));
    }

    /**
     * Creates a builder thats just abstraction over program and can be used with watch
     */
    导出 函数 创建抽象构建器(新程序: 程序_, 主机: 构建程序主机_, 旧程序?: 构建程序_): 构建程序_;
    导出 函数 创建抽象构建器(根名称组: 只读数组_<文字>, 选项组: 编译选项_, 主机?: 编译主机_, 旧程序?: 构建程序_): 构建程序_;
    导出 函数 创建抽象构建器(新程序或根文件名组: 程序_ | 只读数组_<文字>, 主机或选项: 构建程序主机_ | 编译选项_, 旧程序或主机?: 编译主机_ | 构建程序_, 旧程序?: 构建程序_): 构建程序_ {
        常量 { 新程序: 程序 } = 获取构建创建参数(新程序或根文件名组, 主机或选项, 旧程序或主机, 旧程序);
        返回 {
            获取程序: () => 程序,
            获取状态: 未实现,
            获取编译选项: 未实现,
            获取源文件: 未实现,
            获取源文件组: 未实现,
            获取选项诊断信息: 未实现,
            获取全局诊断信息: 未实现,
            获取语法诊断信息: 未实现,
            获取语义诊断信息: 未实现,
            输出: 未实现,
            获取全部诊断信息: 未实现,
            获取当前目录: 未实现
        };
    }
}
